package com.gukun.springboot.tdengine.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.gukun.springboot.tdengine.domain.common.PageParam;
import com.gukun.springboot.tdengine.domain.common.PageResult;
import com.gukun.springboot.tdengine.dto.CustomTableDto;
import com.gukun.springboot.tdengine.dto.SlowSqlParamDto;
import com.gukun.springboot.tdengine.dto.TableDto;
import com.gukun.springboot.tdengine.enums.TdengineEnums;
import com.gukun.springboot.tdengine.pojo.*;
import com.gukun.springboot.tdengine.domain.common.CommonResult;
import com.gukun.springboot.tdengine.domain.common.GlobalErrorCodeConstants;
import com.gukun.springboot.tdengine.service.TDEngineService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.ShowStatement;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.UseStatement;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.show.ShowTablesStatement;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

@RequestMapping("/rtdb/api/v1")
@RestController
public class RtdbController {
    private static final Logger logger = LoggerFactory.getLogger(RtdbController.class);

    @Autowired
    private TDEngineService tdEngineService;

    /**
     * 查询数据库
     *
     * @return 数据库列表
     */
    @Operation(summary = "查询数据库", description = "查询数据库列表")
    @GetMapping("/showDatabases")
    public CommonResult<List<String>> showDatabases(@Parameter(description = "Database configuration", required = true)  DBConfig dbConfig) throws Exception {
        return CommonResult.success(tdEngineService.showDatabases(dbConfig.getHost(), dbConfig.getPort()
                , dbConfig.getUsername(), dbConfig.getPassword()));
    }


    /**
     * 查询超级表
     *
     * @return 超级表列表
     */
    @Operation(summary = "查询超级表", description = "查询超级表列表")
    @GetMapping("/showSTables")
    public CommonResult<List<String>> showSTables(@Parameter(description = "Database configuration", required = true)  DBConfig dbConfig) {
        List<String> result = tdEngineService.showSTables(dbConfig.getHost(), dbConfig.getPort()
                , dbConfig.getUsername(), dbConfig.getPassword(), dbConfig.getDbName());
        if(result == null){
            return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "数据库不存在");
        }

        return CommonResult.success(result);
    }

    /**
     * 删除表格
     * @param params 参数
     * @return 返回结果
     * @throws Exception 全局异常处理
      */
    @Operation(summary = "删除表格", description = "删除表格")
    @PostMapping("/deleteTable")
    public CommonResult<Boolean> deleteTable(@org.springframework.web.bind.annotation.RequestBody JSONObject params) throws Exception {
        DBConfig dbConfig = params.getObject("dbConfig", DBConfig.class);
        String tableName = params.getString("tableName");
        return CommonResult.success(tdEngineService.deleteTable(dbConfig,tableName));
    }

    /**
     * 创建自定义超级表
     * @param customSTableDto 自动表内容
     * @return 创建结果
     */
    @Operation(summary = "创建自定义超级表", description = "创建自定义超级表")
    @PostMapping("/addCustomSuperTable")
    public CommonResult<Boolean> addCustomSuperTable(@org.springframework.web.bind.annotation.RequestBody CustomTableDto customSTableDto) throws Exception{
        return CommonResult.success(tdEngineService.addCustomSuperTable(customSTableDto.getDbConfig(),customSTableDto.getTableDto()));
    }

    /**
     * 创建自定义普通表
     * @param customTableDto 自动表内容
     * @return 创建结果
     */
    @Operation(summary = "创建自定义普通表", description = "创建自定义普通表")
    @PostMapping("/addCustomTable")
    public CommonResult<Boolean> addCustomTable(@org.springframework.web.bind.annotation.RequestBody CustomTableDto customTableDto){
        return CommonResult.success(tdEngineService.addCustomTable(customTableDto.getDbConfig(),customTableDto.getTableDto()));
    }

    /**
     * 创建子表
     * @param customTableDto 子表信息
     * @return 创建结果
     */
    @Operation(summary = "创建子表", description = "创建子表")
    @PostMapping("/addChildTable")
    public CommonResult<Boolean> addChildTable(@org.springframework.web.bind.annotation.RequestBody CustomTableDto customTableDto) throws Exception{
        return CommonResult.success(tdEngineService.addChildTable(customTableDto.getDbConfig(),customTableDto.getTableDto()));
    }

    /**
     * 获取表格字段结构
     * @param customTableDto 数据库信息 表格信息
     * @return 表格字段信息
     */
    @Operation(summary = "获取表格字段结构", description = "获取表格字段结构")
    @PostMapping("/getTableStructure")
    public CommonResult<TableDto> getTableStructure(@org.springframework.web.bind.annotation.RequestBody CustomTableDto customTableDto) throws Exception{
        return CommonResult.success(tdEngineService.getTableStructure(customTableDto));
    }

    /**
     * 创建超级表
     *
     * @return 超级表列表
     */
    @Operation(summary = "创建超级表", description = "创建超级表")
    @PostMapping("/addSuperTable")
    public CommonResult<List<String>> addSuperTable(@RequestBody(description = "创建超级表") @org.springframework.web.bind.annotation.RequestBody DBConfig dbConfig) {
        Boolean result = tdEngineService.addSuperTable(dbConfig.getHost(), dbConfig.getPort()
                , dbConfig.getUsername(), dbConfig.getPassword(), dbConfig.getDbName());
        if(!result){
            return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "数据库不存在");
        }
        return showSTables(dbConfig);
    }

    /**
     * 初始化ti
     *
     * @return 超级表列表
     */
    @Operation(summary = "初始化ti", description = "初始化ti")
    @PostMapping("/initTiTable")
    public CommonResult<List<String>> initTiTable(@RequestBody(description = "创建超级表") @org.springframework.web.bind.annotation.RequestBody DBConfig dbConfig) {
        Boolean result = tdEngineService.initTiTable(dbConfig.getHost(), dbConfig.getPort()
                , dbConfig.getUsername(), dbConfig.getPassword(), dbConfig.getDbName());
        if(!result){
            return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "数据库不存在");
        }
        return showSTables(dbConfig);
    }

    /**
     * 初始化tn
     *
     * @return 超级表列表
     */
    @Operation(summary = "初始化tn", description = "初始化tn")
    @PostMapping("/initTnTable")
    public CommonResult<List<String>> initTnTable(@RequestBody(description = "创建超级表") @org.springframework.web.bind.annotation.RequestBody DBConfig dbConfig) {
        Boolean result = tdEngineService.initTnTable(dbConfig.getHost(), dbConfig.getPort()
                , dbConfig.getUsername(), dbConfig.getPassword(), dbConfig.getDbName());
        if(!result){
            return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "数据库不存在");
        }
        return showSTables(dbConfig);
    }

    /**
     * 转化tn
     *
     * @return 超级表列表
     */
    @Operation(summary = "转化tn", description = "转化tn")
    @PostMapping("/convertTnTable")
    public CommonResult<List<String>> convertTnTable(@RequestBody(description = "创建超级表") @org.springframework.web.bind.annotation.RequestBody DBConfig dbConfig) {
        Boolean result = tdEngineService.convertTnTable(dbConfig.getHost(), dbConfig.getPort()
                , dbConfig.getUsername(), dbConfig.getPassword(), dbConfig.getDbName());
        if(!result){
            return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "数据库不存在");
        }
        return showSTables(dbConfig);
    }

    /**
     * 根据超表查询子表
     *
     * @return 表列表
     */
    @Operation(summary = "根据超表查询子表", description = "根据超表查询子表")
    @GetMapping("/showTablesBySTable")
    public CommonResult<List<String>> showTablesBySTable(@Parameter(description = "Database configuration", required = true)  DBConfig dbConfig,
                                                         @Parameter(description = "超级表名", required = true)  String stableName) {
        List<String> result = tdEngineService.showTablesBySTable(dbConfig.getHost(), dbConfig.getPort()
                , dbConfig.getUsername(), dbConfig.getPassword(), dbConfig.getDbName(), stableName);
        if(result == null){
            return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "数据库不存在");
        }

        return CommonResult.success(result);
    }


    /**
     * 根据超表查询子表
     *
     * @return 表列表
     */
    @Operation(summary = "获取所有子表", description = "获取所有子表")
    @GetMapping("/showTables")
    public CommonResult<List<String>> showTables(@Parameter(description = "Database configuration", required = true)  DBConfig dbConfig,
                                               @Parameter(description = "过滤条件",required = false)  String filter) {
        List<String> result = tdEngineService.showTables(dbConfig.getHost(), dbConfig.getPort()
                , dbConfig.getUsername(), dbConfig.getPassword(), dbConfig.getDbName(), filter);

        if(result == null){
            return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "数据库不存在");
        }
        Collections.sort(result);
        return CommonResult.success(result);
    }

    /**
     * 分页获取表格
     */
    @Operation(summary = "分页查询表格", description = "根据分页、名称、数据库名称、超级表等条件查询表格")
    @PostMapping("/getTableByPage")
    public CommonResult<PageResult<TableDto>> getTableByPage(@org.springframework.web.bind.annotation.RequestBody String params){
        JSONObject jsonObject = JSONObject.parseObject(params);
        DBConfig dbConfig = jsonObject.getObject("dbConfig", DBConfig.class);
        String filterName = jsonObject.getString("filterName");
        String likeDesc = jsonObject.getString("likeDesc");
        //用于获取某个超表的子表
        String superTableName = jsonObject.getString("superTableName");
        //是否获取超表
        boolean isSuperTable = jsonObject.getBoolean("isSuperTable");
        PageParam page = jsonObject.getObject("page", PageParam.class);
        //是否获取值
        boolean needLastValue = jsonObject.getBooleanValue("needLastValue");
        return CommonResult.success(tdEngineService.getTableByPage(dbConfig,filterName,page,superTableName,isSuperTable,likeDesc,needLastValue));
    }

    /**
     * 查询tdengine历史数据
     */
    @Operation(summary = "查询tdengine历史数据", description = "查询tdengine历史数据")
    @PostMapping("/queryHistoryData")
    public CommonResult<PageResult<TagData>> queryHistoryData(@RequestBody(description = "查询数据的参数")
                                                                  @org.springframework.web.bind.annotation.RequestBody QueryHisDataInput queryHisDataInput) {
        try {
            PageResult<TagData> result = tdEngineService.queryHistoryData(queryHisDataInput);
            if(result == null){
                return CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "查询出错！");
            }

            return CommonResult.success(result);
        }catch (Exception e){
            logger.error("查询出错", e);
            return CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "查询出错！");
        }
    }


    @PostMapping("/exportData")
    public void exportData(@org.springframework.web.bind.annotation.RequestBody QueryHisDataInput queryHisDataInput) throws IOException, SQLException {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        HttpServletRequest request =  ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();

        Workbook workbook = tdEngineService.exportData(queryHisDataInput);
        // 设置响应头
        response.setHeader("Content-Disposition", "attachment; filename=\"data.xlsx\"");
        response.setStatus(HttpServletResponse.SC_OK);

        // 写入响应流
        workbook.write(response.getOutputStream());
        workbook.close();
    }

    /**
     * 查询tdengine历史数据
     */
    @Operation(summary = "查询tdengine历史数据", description = "查询tdengine历史数据")
    @PostMapping("/batchQueryHistoryData")
    public CommonResult<Map<String,List<TagData>>> batchQueryHistoryData(@RequestBody(description = "查询数据的参数")
                                                              @org.springframework.web.bind.annotation.RequestBody QueryHisDataInput queryHisDataInput) {
        try {
            Map<String,List<TagData>> result = tdEngineService.batchQueryHistoryData(queryHisDataInput);
            if(result == null){
                return CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "查询出错！");
            }

            return CommonResult.success(result);
        }catch (Exception e){
            logger.error("查询出错", e);
            return CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "查询出错！");
        }
    }


    /**
     * 查询数据
     *
     * @return 表列表
     */
    @Operation(summary = "查询数据", description = "查询表列表")
    @PostMapping("/executeSQL")
    public CommonResult< List<List<String>>> executeSQL(@RequestBody(description = "查询数据的参数")
                                                            @org.springframework.web.bind.annotation.RequestBody ExcuteQueryInput excuteQueryInput) {

        try {
            String sql = excuteQueryInput.getSql();
            Statement parse = CCJSqlParserUtil.parse(sql);
            if(!StrUtil.isEmpty(sql) && (parse instanceof Select
                    || parse instanceof ShowTablesStatement
                    || parse instanceof ShowStatement
                    || parse instanceof UseStatement)) {
                //如果是select语句，添加limit
                if(parse instanceof Select){
                    sql = sql + " limit 100000";
                    excuteQueryInput.setSql(sql);
                }
                List<List<String>> lists = tdEngineService.executeSQL(excuteQueryInput.getDbConfig().getHost(), excuteQueryInput.getDbConfig().getPort()
                        , excuteQueryInput.getDbConfig().getUsername(), excuteQueryInput.getDbConfig().getPassword(),
                        excuteQueryInput.getDbConfig().getDbName(), excuteQueryInput.getSql());

                return CommonResult.success(lists);
            }else {
                return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "sql 必须是select,show table语句。");
            }
        } catch (JSQLParserException e) {
            logger.error("sql 语法错误", e);
            return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), "sql 语法错误");
        }
    }

    /**
     * 修改表结构
     */
    @Operation(summary = "修改表结构", description = "修改超级表、普通表表结构")
    @PostMapping("/alterTable")
    public CommonResult<TableDto> alterTable(@org.springframework.web.bind.annotation.RequestBody String params) throws Exception{
        JSONObject jsonObject = JSONObject.parseObject(params);
        DBConfig dbConfig = jsonObject.getObject("dbConfig", DBConfig.class);
        String tableName = jsonObject.getString("tableName");
        ColumnVo columnVo = jsonObject.getObject("columnInfo", ColumnVo.class);
        TdengineEnums fieldType = TdengineEnums.valueOf(jsonObject.getString("fieldType"));
        TdengineEnums tableType = TdengineEnums.valueOf(jsonObject.getString("tableType"));
        int operation = jsonObject.getInteger("operation");
        return CommonResult.success(tdEngineService.alterTable(dbConfig,columnVo,tableName,fieldType,operation,tableType));
    }

    /**
     * 创建数据库
     */
    @Operation(summary = "创建数据库", description = "创建数据库")
    @PostMapping("/createDatabase")
    public CommonResult<Boolean> createDatabase(@org.springframework.web.bind.annotation.RequestBody DBConfig dbConfig) throws Exception {
        return CommonResult.success(tdEngineService.createDatabase(dbConfig));
    }

    @Operation(summary = "获取节点信息",description = "数据节点，管理节点，计算节点")
    @PostMapping("/getNodesInfo")
    public CommonResult<List<List<String>>> getNodesInfo(@org.springframework.web.bind.annotation.RequestBody String data) throws Exception{
        JSONObject jsonObject = JSONObject.parseObject(data);
        DBConfig dbConfig = jsonObject.getObject("dbConfig", DBConfig.class);
        String type = jsonObject.getString("type");
        return CommonResult.success(tdEngineService.getNodesInfo(dbConfig,type));
    }

    @Operation(summary = "新增节点",description = "数据节点，管理节点，计算节点")
    @PostMapping("/addNode")
    public CommonResult<Boolean> addNode(@org.springframework.web.bind.annotation.RequestBody String data) throws Exception{
        JSONObject jsonObject = JSONObject.parseObject(data);
        DBConfig dbConfig = jsonObject.getObject("dbConfig", DBConfig.class);
        String type = jsonObject.getString("type");
        String dnodeEndpoint = jsonObject.getString("dnodeEndpoint");
        String dNodeId = jsonObject.getString("dNodeId");
        return CommonResult.success(tdEngineService.addNode(dbConfig,type,dnodeEndpoint,dNodeId));
    }

    @Operation(summary = "删除节点",description = "数据节点，管理节点，计算节点")
    @PostMapping("/deleteNode")
    public CommonResult<Boolean> deleteNode(@org.springframework.web.bind.annotation.RequestBody String data) throws Exception{
        JSONObject jsonObject = JSONObject.parseObject(data);
        DBConfig dbConfig = jsonObject.getObject("dbConfig", DBConfig.class);
        String type = jsonObject.getString("type");
        String dNodeId = jsonObject.getString("dNodeId");
        return CommonResult.success(tdEngineService.deleteNode(dbConfig,type,dNodeId));
    }

    @Operation(summary = "慢SQL明细",description = "分页查询慢SQL信息")
    @PostMapping("/getSlowSqlByPage")
    public CommonResult<PageResult<List<String>>> getSlowSqlByPage(@org.springframework.web.bind.annotation.RequestBody SlowSqlParamDto slowSqlParamDto) throws Exception{
        return CommonResult.success(tdEngineService.getSlowSqlByPage(slowSqlParamDto));
    }

    @Operation(summary = "慢SQL统计",description = "分页查询慢SQL统计信息")
    @PostMapping("/getStatisticalSlowSqlByPage")
    public CommonResult<PageResult<List<String>>> getStatisticalSlowSqlByPage(@org.springframework.web.bind.annotation.RequestBody SlowSqlParamDto slowSqlParamDto) throws Exception{
        return CommonResult.success(tdEngineService.getStatisticalSlowSqlByPage(slowSqlParamDto));
    }

    @PostMapping("updateTsValue")
    public CommonResult<Boolean> updateTsValue(@org.springframework.web.bind.annotation.RequestBody String data) throws Exception{
        return CommonResult.success(tdEngineService.updateTsValue(data));
    }
}
